import java.util.HashMap;
import java.util.HashSet;

// 名为Code01_HashSetAndHashMap的类
public class Code01_HashSetAndHashMap {
    public static void main(String[] args) {
        // 对于Java中的包装类（如Integer、Long、Double、Float、Byte、Short、Character、Boolean）以及String类
        // 有一些特殊的比较特性

        // 创建两个内容相同但内存地址不同的String对象
        String str1 = new String("Hello");
        String str2 = new String("Hello");

        // "=="比较的是对象的内存地址，由于str1和str2是不同的对象实例，所以结果为false
        System.out.println(str1 == str2);
        // "equals"方法在String类中被重写，用于比较字符串内容，所以结果为true
        System.out.println(str1.equals(str2));

        // 创建一个HashSet，用于存储String类型的元素
        HashSet<String> set = new HashSet<>();
        // 向HashSet中添加str1
        set.add(str1);
        // 由于HashSet在判断元素是否存在时，是根据元素的hashCode和equals方法来判断的
        // "Hello"和str1的内容相同，所以会返回true
        System.out.println(set.contains("Hello"));
        // 同理，str2的内容和str1相同，所以也会返回true
        System.out.println(set.contains(str2));
        // 向HashSet中添加str2，由于HashSet的元素唯一性，不会重复添加，所以集合大小仍然为1
        set.add(str2);
        System.out.println(set.size());
        // 从HashSet中移除str1
        set.remove(str1);
        // 清空HashSet中的所有元素
        set.clear();
        // 判断HashSet是否为空，由于已经清空，所以结果为true
        System.out.println(set.isEmpty());

        System.out.println("===========");

        // 创建一个HashMap，键和值都是String类型
        HashMap<String, String> map1 = new HashMap<>();
        // 向HashMap中添加键值对，键为str1，值为"World"
        map1.put(str1, "World");
        // 由于HashMap在判断键是否存在时，也是根据键的hashCode和equals方法来判断的
        // "Hello"和str1的内容相同，所以会返回true
        System.out.println(map1.containsKey("Hello"));
        // 同理，str2的内容和str1相同，所以也会返回true
        System.out.println(map1.containsKey(str2));
        // 获取键为str2对应的值，由于键str1和str2内容相同，所以能获取到值"World"
        System.out.println(map1.get(str2));
        // 由于HashMap中不存在键为"你好"的键值对，所以结果为true
        System.out.println(map1.get("你好") == null);
        // 从HashMap中移除键为"Hello"的键值对
        map1.remove("Hello");
        // 输出HashMap的大小，由于移除了一个键值对，所以大小为0
        System.out.println(map1.size());
        // 清空HashMap中的所有键值对
        map1.clear();
        // 判断HashMap是否为空，由于已经清空，所以结果为true
        System.out.println(map1.isEmpty());

        System.out.println("===========");

        // 创建一个HashMap，键为Integer类型，值为Integer类型
        HashMap<Integer, Integer> map2 = new HashMap<>();
        // 向HashMap中添加键值对
        map2.put(56, 7285);
        map2.put(34, 3671263);
        map2.put(17, 716311);
        map2.put(24, 1263161);

        // 如果键的范围是固定的、可控的，那么可以使用数组来替代哈希表的功能
        // 创建一个长度为100的整数数组
        int[] arr = new int[100];
        // 通过数组索引来模拟哈希表的键值对存储，将值赋给对应的索引位置
        arr[56] = 7285;
        arr[34] = 3671263;
        arr[17] = 716311;
        arr[24] = 1263161;
        // 在笔试场景中，当满足上述条件时，哈希表的功能往往可以被数组替代
        System.out.println("在笔试场合中哈希表往往会被数组替代");

        System.out.println("===========");

        // 创建一个内部类Student的两个实例，这两个实例的age和name属性相同
        Student s1 = new Student(17, "张三");
        Student s2 = new Student(17, "张三");
        // 创建一个HashMap，键为Student类型，值为String类型
        HashMap<Student, String> map3 = new HashMap<>();
        // 向HashMap中添加键值对，键为s1，值为"这是张三"
        map3.put(s1, "这是张三");
        // 由于HashMap判断键是否存在是根据键对象的hashCode和equals方法
        // 而默认情况下Student类没有重写这两个方法，s1和s2是不同的对象实例，所以这里返回true
        System.out.println(map3.containsKey(s1));
        // 这里返回false，因为默认的对象比较是基于内存地址，s2和s1内存地址不同
        System.out.println(map3.containsKey(s2));
        // 向HashMap中添加键为s2的键值对，由于Student类没有合适的hashCode和equals方法重写
        // 所以会当作不同的键处理，此时map3的大小变为2
        map3.put(s2, "这是另一个张三");
        System.out.println(map3.size());
        // 获取键为s1对应的值并输出
        System.out.println(map3.get(s1));
        // 获取键为s2对应的值并输出
        System.out.println(map3.get(s2));
    }

    // 内部类Student，用于表示学生，包含年龄和姓名两个属性
    public static class Student {
        public int age;
        public String name;

        // 学生类的构造函数，用于初始化年龄和姓名属性
        public Student(int a, String b) {
            age = a;
            name = b;
        }
    }
}